package com.stefanhermann.graphicstest;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.FloatMath;
import android.view.View;

public class MyGraphicsView extends View {

	Random rand = new Random();
	int r, g, b, rSign, gSign, bSign;

	byte mode = 1;
	private final float PICKTOLERANCE = 20; // Tolerance when picking a line
	int selectedLine; // Selected line when moving
	byte handleMoveEvent;

	// Coordinates for movement
	float moveX, moveY;

	Bitmap particle;
	Bitmap btLogo;
	Bitmap deleteButton;
	Bitmap createLineButton;
	Bitmap moveLineButton;

	Paint linePaint;
	Paint selectedLinePaint;
	Paint handlePaint;
	Paint createLinePaint;

	List<Line> lineList = new ArrayList<Line>();
	Line selLine;
	Line createdLine;

	public MyGraphicsView(Context context) {
		super(context);

		// /Particle
		try {
			AssetManager assetManager = context.getAssets();
			InputStream inputStream = assetManager.open("particle.png");
			particle = BitmapFactory.decodeStream(inputStream);
			inputStream.close();
		} catch (IOException e) {
		}

		// /btLogo
		Resources resources = getResources();
		btLogo = BitmapFactory.decodeResource(resources, R.drawable.btlogo);

		// Bitmaps
		deleteButton = BitmapFactory.decodeResource(resources, R.drawable.delete);
		createLineButton = BitmapFactory.decodeResource(resources, R.drawable.linecreate);
		moveLineButton = BitmapFactory.decodeResource(resources, R.drawable.move);

		// /Other stuff
		r = rand.nextInt(255);
		g = rand.nextInt(255);
		b = rand.nextInt(255);
		rSign = -1;
		bSign = -1;
		gSign = -1;

		linePaint = new Paint();
		linePaint.setColor(Color.YELLOW);
		linePaint.setStrokeWidth(5f);
		linePaint.setAntiAlias(true);

		createLinePaint = new Paint();
		createLinePaint.setColor(Color.GREEN);
		createLinePaint.setStrokeWidth(5f);
		createLinePaint.setAntiAlias(true);

		selectedLinePaint = new Paint();
		selectedLinePaint.setColor(Color.BLUE);
		selectedLinePaint.setStrokeWidth(10f);
		selectedLinePaint.setAntiAlias(true);

		handlePaint = new Paint();
		handlePaint.setColor(Color.WHITE);
		handlePaint.setAntiAlias(true);

	}

	@Override
	protected void onDraw(Canvas canvas) {
		if (r >= 240 || r <= 10)
			rSign *= (-1);
		if (g >= 240 || g <= 10)
			gSign *= (-1);
		if (b >= 240 || b <= 10)
			bSign *= (-1);
		r += 5 * rSign;
		g += 5 * gSign;
		b += 5 * bSign;
		canvas.drawRGB(r, g, b);

		if (mode == 1)
			canvas.drawBitmap(createLineButton, 0, 0, null);
		else if (mode == 0)
			canvas.drawBitmap(deleteButton, 0, 0, null);
		else
			canvas.drawBitmap(moveLineButton, 0, 0, null);

		for (Line cLine : lineList) {
			canvas.drawLine(cLine.x1, cLine.y1, cLine.x2, cLine.y2, linePaint);
		}

		if (selLine != null) {
			canvas.drawLine(selLine.x1, selLine.y1, selLine.x2, selLine.y2, selectedLinePaint);
			// Draw handles
			canvas.drawCircle(selLine.x1, selLine.y1, 10, handlePaint);
			canvas.drawCircle(selLine.x2, selLine.y2, 10, handlePaint);
		}

		// Preview created line
		if (createdLine != null)
			canvas.drawLine(createdLine.x1, createdLine.y1, createdLine.x2, createdLine.y2, createLinePaint);

		invalidate();
	}

	public void updateLines(Line line) {
		lineList.add(line);
	}

	public int findTouchedLine(float x, float y) {
		float tempDistance;
		float firstDistance;

		for (int i = 0; i < lineList.size(); i++) {
			if (getLinePointDistance(lineList.get(i).x1, lineList.get(i).y1, lineList.get(i).x2, lineList.get(i).y2, x, y) < PICKTOLERANCE) {
				tempDistance = getPointDistance(lineList.get(i).x1, lineList.get(i).y1, lineList.get(i).x2, lineList.get(i).y2);
				firstDistance = getPointDistance(lineList.get(i).x1, lineList.get(i).y1, x, y);
				if (firstDistance <= tempDistance + PICKTOLERANCE) {
					if (getPointDistance(lineList.get(i).x2, lineList.get(i).y2, x, y) <= tempDistance + PICKTOLERANCE) {
						return i;
					}
				}
			}
		}
		return -1;
	}

	public void getTouchInput(float x1, float y1, float x2, float y2) {
		// ####Check the touched location
		// Switch mode

		// reset
		handleMoveEvent = -1;

		if (x1 < 100 && y1 < 100 && x2 < 100 && y2 < 100) {
			if (mode >= 2)
				mode = 0;
			else
				mode++;
			// Add selectedLine to normal lines
			if (selLine != null) {
				lineList.add(selLine);
				selLine = null;
			}
		} else if (mode == 1 && getPointDistance(x1, y1, x2, y2) > PICKTOLERANCE) { // If
																					// in
																					// creation
																					// mode
			updateLines(createdLine);
			createdLine = null;
		} else if (mode == 0) { // If in delete mode
			selectedLine = findTouchedLine(x2, y2);
			if (selectedLine >= 0) {
				lineList.remove(selectedLine);
			}
		} else if (mode == 2) {
			// A selection should just be if the drag distance was lower than
			// the PICKTOLERANCE
			if (getPointDistance(x1, y1, x2, y2) < PICKTOLERANCE) {
				// Set start-coordinates
				moveX = x1;
				moveY = y1;

				selectedLine = findTouchedLine(x2, y2);
				if (selectedLine >= 0) {
					// If one is already selected get it back into the list
					if (selLine != null) {
						lineList.add(selLine);
						selLine = null;
					}

					selLine = lineList.get(selectedLine);
					lineList.remove(selectedLine);
				}
			}

		}

	}

	public static float getLinePointDistance(float x1, float y1, float x2, float y2, float x3, float y3) {
		// / ATTENTION ----> line can not be vertical!!
		if (x1 == x2)
			x1++; // workaround

		float a = (y2 - y1) / (x2 - x1);
		float b = -1f;
		float c = y1 - a * x1;
		float distance = Math.abs(a * x3 + b * y3 + c) / FloatMath.sqrt(a * a + b * b);
		return distance;
	}

	public static float getPointDistance(float x1, float y1, float x2, float y2) {
		return FloatMath.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
	}

	public void moveLine(float x, float y) {
		// See if handle was picked
		if (handleMoveEvent == -1 && selLine != null) {
			if (getPointDistance(moveX, moveY, selLine.x1, selLine.y1) < (PICKTOLERANCE * 1.5))
				handleMoveEvent = 1;
			else if (getPointDistance(moveX, moveY, selLine.x2, selLine.y2) < (PICKTOLERANCE * 1.5))
				handleMoveEvent = 2;
			else
				handleMoveEvent = 0;
		}

		if (moveX > 0 && moveY > 0 && (x > 100 || y > 100)) {
			float moveVectorX = x - moveX;
			float moveVectorY = y - moveY;

			// Error check
			if (selLine != null) {
				if (handleMoveEvent == 0) {
					selLine.x1 += moveVectorX;
					selLine.x2 += moveVectorX;
					selLine.y1 += moveVectorY;
					selLine.y2 += moveVectorY;
				} else if (handleMoveEvent == 1) {
					selLine.x1 += moveVectorX;
					selLine.y1 += moveVectorY;
				} else {
					selLine.x2 += moveVectorX;
					selLine.y2 += moveVectorY;
				}
			}
		}
		moveX = x;
		moveY = y;
	}

	public void createLine(float x1, float y1, float x2, float y2) {
		if (!(x1 < 100 && y1 < 100)) {
			if (createdLine == null)
				createdLine = new Line(x1, y1, x2, y2);
			else {
				createdLine.x2 = x2;
				createdLine.y2 = y2;
			}
		}
	}
}
